òɾۿûѧϰʹá
ԭַhttps://www.joinquant.com/post/11549

ԭһ˵ʽ鵽ԭĺ߽ۡ


ԭĲԴ£

'''
һ ƣPBֵͶʲ
 ԸɸѡоҲָõAɣֵͶ
 Իݣ
    1 ѡɣɸѡAбԷĹƱҪ
        1.1 ״̬ˣ̡ͣСSTͣɣ
        1.2 ɸѡɸѡͨɱС25ڹɡоС0.85ӪҵͬʡͬʡʲROE
                      0ĹƱԳɸѡĹƱоʴСɸѡǰ10ֻƱ10ֻ
        1.3 򣺶ѡĹƱʲROEоʡͬʡֵָռȨر
    2 ʱһĹƱ쿪̼
    3 λͬʱһֻƱֻȫ
    4 ֹӯֹÿжϸɴӳֲֺǵȼ߼ۻسȣ趨ֵ
 Իز
    1 زڣ2014-01-01  2018-01-30 ӻز
    2 ʼʽ100000Ԫ
    3 棺1465.70% 껯棺99.19% Alpha0.908 Beta0.357 Sharpe3.149 ʤʣ100% ز⣺15.860%
 ԻĽ
    1 ղʱ϶࣬ռ˻زڵ֮һʱ䣬д
    2 ̽ǷиʺϸòԵĲλ
    3 ̬ӣĿǰɸѡΪزЧ

汾1.3.1.180318
ڣ2018.3.18
ߣĸ
'''

# 뺯
from kuanke.wizard import *
from jqdata import *
import numpy as np
import pandas as pd
import talib
import datetime

## ʼ趨ҪĹƱ׼ȵ
def initialize(context):
    # 趨׼
    set_benchmark('000300.XSHG')
    # 趨(̶ֵ0.02Ԫ)ʱӼ۲һ룬̶ֵ0.02ԪʱԶӼ0.01Ԫ
    set_slippage(FixedSlippage(0.02))
    # TrueΪ̬Ȩģʽʹʵ۸ףÿõĳȨ۸ǰȡǰڵڵǰȨ۸
    set_option('use_real_price', True) 
    # 趨ɽΪ100%ʵÿĳɽɽÿճɽ*ÿճɽ
    set_option('order_volume_ratio', 1)
    # ƱཻǣʱӶ֮ʱӶ֮ǧ֮һӡ˰, ÿʽӶͿ5Ǯ
    set_order_cost(OrderCost(open_tax=0, close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
    # ѡƵ
    g.check_stocks_refresh_rate = 1
    # ƵʡƵ
    g.buy_refresh_rate , g.sell_refresh_rate = 1 , 1
    # 󽨲
    g.max_hold_stocknum = 1
    # ֱֲ
    g.security_max_proportion = 1
    # ѡƵʼ
    g.check_stocks_days = 0 
    # Ƶʼ
    g.buy_trade_days , g.sell_trade_days = 0 , 0
    # ȡδĹƱ
    g.open_sell_securities = [] 
    # Ʊdict
    g.selled_security_list={}
    # ƱɸѡʼǷ̡ͣǷСǷST
    g.filter_paused , g.filter_delisted , g.filter_st = True , True , True
    # Ʊ
    g.security_universe_index = ["all_a_securities"]
    g.security_universe_user_securities = []
    # Ʊɸѡʼ׼ desc-asc-
    g.check_out_lists_ascending = 'desc'
    # ʼ(趨Ƿbuy_listsеĹƱ趨̶ֵ߰ٷֱ)
    g.sell_will_buy , g.sell_by_amount , g.sell_by_percent = True , None , None
    # 볡ʼ趨Ƿظ롢ֻƱԪɣ
    g.filter_holded , g.max_buy_value , g.max_buy_amount = True , None , None

    # رʾ
    log.set_level('order', 'error')
    # к
    run_daily(sell_every_day,'every_bar') #δɹĹƱ
    run_daily(risk_management, 'every_bar') #տ
    run_daily(check_stocks, 'open') #ѡɲ
    run_daily(trade, 'open') #ףʱ
    run_daily(selled_security_list_count, 'after_close') #Ʊڼ 
    

## δɹĹƱ
def sell_every_day(context):
    open_sell_securities = [s for s in context.portfolio.positions.keys() if s in g.open_sell_securities]
    if len(open_sell_securities)>0:
        for stock in open_sell_securities:
            order_target_value(stock, 0)
    return

## 
def risk_management(context):
    # жǷbuy_listsеĹƱ
    if not g.sell_will_buy:
        sell_lists = [security for security in sell_lists if security not in buy_lists]
    # ȡ sell_lists б
    risk_init_sl = context.portfolio.positions.keys()
    risk_sell_lists = context.portfolio.positions.keys()
    # ֹӯʡ30%ʱᶨУֱ4%ʱָùƱҲֹã
    if len(risk_sell_lists) > 0:
        for security in risk_sell_lists:
            # 㵥ֻƱɼ۴ӽǰ߼ͼۣȡÿ
            df_price = get_price(security, start_date=context.portfolio.positions[security].init_time, end_date=context.current_dt, frequency='1m', fields=['high','low'])
            highest_price = df_price['high'].max()
            lowest_price = df_price['low'].min()    
            # ֻƱɼ۴ӽǰ߼ͼٷֱȡ30%4%ʱָùƱȡÿ
            if (highest_price - lowest_price) / lowest_price >= 0.3 \
                    and (highest_price - context.portfolio.positions[security].price) / highest_price >= 0.04:
                # ùйƱ
                order_target_value(security, 0)
    # ȡĹƱ, 뵽 g.selled_security_list
    selled_security_list_dict(context,risk_init_sl)
    return

## Ʊɸѡ
def check_stocks(context):
    if g.check_stocks_days%g.check_stocks_refresh_rate != 0:
        # һ
        g.check_stocks_days += 1
        return
    # Ʊظֵ
    g.check_out_lists = get_security_universe(context, g.security_universe_index, g.security_universe_user_securities)
    # STƱ
    g.check_out_lists = st_filter(context, g.check_out_lists)
    # йƱ
    g.check_out_lists = delisted_filter(context, g.check_out_lists)
    # ͣƹƱ
    g.check_out_lists = paused_filter(context, g.check_out_lists)
    # ͣƱ
    g.check_out_lists = high_limit_filter(context, g.check_out_lists)
    # ɸѡ
    g.check_out_lists = financial_statements_filter(context, g.check_out_lists)
    # ɸѡĹƱоʴСųǰ10ֻƱ
    df_check_out_lists = get_fundamentals(query(
            valuation.code, valuation.pb_ratio
        ).filter(
            # ﲻʹ in , Ҫʹin_()
            valuation.code.in_(g.check_out_lists)
        ).order_by(
            # оУ׼desc-asc-
            valuation.pb_ratio.asc()
        ).limit(
            # ෵10
            10
            #ǰһյ
        ), date=context.previous_date)
    # ɸѡg.check_out_lists
    g.check_out_lists = df_check_out_lists['code']
    #     
    input_dict = get_check_stocks_sort_input_dict()
    g.check_out_lists = check_stocks_sort(context,g.check_out_lists,input_dict,g.check_out_lists_ascending)
    # һ
    g.check_stocks_days = 1
    return

## ׺
def trade(context):
    # ȡ buy_lists б
    buy_lists = g.check_out_lists
    # 
    if g.sell_trade_days%g.sell_refresh_rate != 0:
        # һ
        g.sell_trade_days += 1
    else:
        # Ʊ
        sell(context, buy_lists)
        # һ
        g.sell_trade_days = 1
    # 
    if g.buy_trade_days%g.buy_refresh_rate != 0:
        # һ
        g.buy_trade_days += 1
    else:
        # Ʊ
        buy(context, buy_lists)
        # һ
        g.buy_trade_days = 1

## Ʊڼ
def selled_security_list_count(context):
    if len(g.selled_security_list)>0:
        for stock in g.selled_security_list.keys():
            g.selled_security_list[stock] += 1

##################################  ѡȺ ##################################
# ȡƱƱ
def get_security_universe(context, security_universe_index, security_universe_user_securities):
    temp_index = []
    for s in security_universe_index:
        if s == 'all_a_securities':
            temp_index += list(get_all_securities(['stock'], context.current_dt.date()).index)
        else:
            temp_index += get_index_stocks(s)
    for x in security_universe_user_securities:
        temp_index += x
    return  sorted(list(set(temp_index)))

## STƱ
def st_filter(context, security_list):
    if g.filter_st:
        current_data = get_current_data()
        security_list = [stock for stock in security_list if not current_data[stock].is_st]
    # ؽ
    return security_list

## йƱ
def delisted_filter(context, security_list):
    if g.filter_delisted:
        current_data = get_current_data()
        security_list = [stock for stock in security_list if not (('' in current_data[stock].name) or ('*' in current_data[stock].name))]
    # ؽ
    return security_list

## ͣƹƱ
def paused_filter(context, security_list):
    if g.filter_paused:
        current_data = get_current_data()
        security_list = [stock for stock in security_list if not current_data[stock].paused]
    # ؽ
    return security_list

# ͣƱ
def high_limit_filter(context, security_list):
    current_data = get_current_data()
    security_list = [stock for stock in security_list if not (current_data[stock].day_open >= current_data[stock].high_limit)]
    # ؽ
    return security_list

## ָɸѡ
def financial_statements_filter(context, security_list):
    # ͨɱС250000
    security_list = financial_data_filter_xiaoyu(security_list, valuation.circulating_cap, 250000)
    # оС0.85
    security_list = financial_data_filter_xiaoyu(security_list, valuation.pb_ratio, 0.85)
    # Ӫҵͬ(%)й˾ȥһǮǷߵı׼
    security_list = financial_data_filter_dayu(security_list, indicator.inc_revenue_year_on_year, 0)
    # ͬʣڵľ-£꣩ڵľ/£꣩ڵľ=ͬ
    security_list = financial_data_filter_dayu(security_list, indicator.inc_net_profit_year_on_year, 0)
    # ʲROEĸ˾ɶľ*2/ڳĸ˾ɶľʲ+ĩĸ˾ɶľʲ
    security_list = financial_data_filter_dayu(security_list, indicator.roe, 0)
    # б
    return security_list

# ȡѡ input_dict
def get_check_stocks_sort_input_dict():
    #desc-asc-
    input_dict = {
        indicator.roe:('desc',0.7), #ʲROEӴСȨ0.7
        valuation.pb_ratio:('asc',0.05), #оʣСȨ0.05
        indicator.inc_net_profit_year_on_year:('desc',0.2), #ͬʣӴСȨ0.2
        valuation.market_cap:('desc',0.05), #ֵӴСȨ0.05
        }
    # ؽ
    return input_dict

## 
def check_stocks_sort(context,security_list,input_dict,ascending='desc'):
    if (len(security_list) == 0) or (len(input_dict) == 0):
        return security_list
    else:
        #  key  list
        idk = list(input_dict.keys())
        # ɾ
        a = pd.DataFrame()
        for i in idk:
            b = get_sort_dataframe(security_list, i, input_dict[i])
            a = pd.concat([a,b],axis = 1)
        #  score 
        a['score'] = a.sum(1,False)
        #  score 
        if ascending == 'asc':# 
            a = a.sort(['score'],ascending = True)
        elif ascending == 'desc':# 
            a = a.sort(['score'],ascending = False)
        # ؽ
        return list(a.index)

##################################  ׺Ⱥ ##################################
# ׺ - 
def sell(context, buy_lists):
    # ȡ sell_lists б
    init_sl = context.portfolio.positions.keys()
    sell_lists = context.portfolio.positions.keys()
    # жǷbuy_listsеĹƱ
    if not g.sell_will_buy:
        sell_lists = [security for security in sell_lists if security not in buy_lists]
    # ĹƱ
    if len(sell_lists)>0:
        for security in sell_lists:
            # 㵥ֻƱɼ۴ӽǰ߼ͼۣȡÿ
            df_price = get_price(security, start_date=context.portfolio.positions[security].init_time, end_date=context.current_dt, frequency='1m', fields=['high','low'])
            highest_price = df_price['high'].max()
            lowest_price = df_price['low'].min() 
            #ֻƱɼ۴ӽǰ߼ͼٷֱ<30%ҳﵽ83ʱָùƱ
            if (highest_price - lowest_price) / lowest_price < 0.3 and max_hold_days(context, security, 83): 
                sell_by_amount_or_percent_or_none(context, security, g.sell_by_amount, g.sell_by_percent, g.open_sell_securities)
    # ȡĹƱб, 뵽 g.selled_security_list 
    selled_security_list_dict(context,init_sl)
    return

# ׺ - 볡
def buy(context, buy_lists):
    # жǷظ
    buy_lists = holded_filter(context,buy_lists)
    # ȡյ buy_lists б
    Num = g.max_hold_stocknum - len(context.portfolio.positions)
    buy_lists = buy_lists[:Num]
    # Ʊ
    if len(buy_lists)>0:
        # ʽ
        result = order_style(context,buy_lists,g.max_hold_stocknum)
        
        for stock in buy_lists:
            if len(context.portfolio.positions) < g.max_hold_stocknum:
                # ȡʽ
                Cash = result[stock]
                # жϸֱֲ
                value = judge_security_max_proportion(context,stock,Cash,g.security_max_proportion)
                # жϵֻ
                amount = max_buy_value_or_amount(stock,value,g.max_buy_value,g.max_buy_amount)
                # µ
                order(stock, amount, MarketOrderStyle())
    return

## Ƿظ
def holded_filter(context,security_list):
    if not g.filter_holded:
        security_list = [stock for stock in security_list if stock not in context.portfolio.positions.keys()]
    # ؽ
    return security_list

## Ʊdict
def selled_security_list_dict(context,security_list):
    selled_sl = [s for s in security_list if s not in context.portfolio.positions.keys()]
    if len(selled_sl)>0:
        for stock in selled_sl:
            g.selled_security_list[stock] = 0

###################################  Ⱥ ##################################


'''
------------------------------  汾˵  ----------------------------------

£

2018.03.18  PBֵͶʲ_1.3.1.180318
    ŻŰ棬Ը
زڣ2014-01-01  2018-01-30 ӻز
棺1465.70% 껯棺99.19% Alpha0.908 Beta0.357 Sharpe3.149 ʤʣ100% ز⣺15.860%

2018.03.11  PBֵͶʲ_1.3.0.180311 
    ޳ɶȨϼƴ25Ԫѡָ꣬
    ӪҵͬʡͬʡʲROE0ѡָ
    ԲɸѡĹƱоʴСٴɸѡ
    ȥ볡ɸѡ
زڣ2014-01-01  2018-01-30 ӻز
棺1465.70% 껯棺99.19% Alpha0.908 Beta0.357 Sharpe3.149 ʤʣ100% ز⣺15.860%

2018.03.09  PBֵͶʲ_1.2.0.180309
    ȥֹֹӯеǷΪǵɼֹ״̬
زڣ2014-01-01  2018-01-30 ӻز
棺1068.39% 껯棺85.11% Alpha0.740 Beta0.578 Sharpe2.705 ʤʣ93.3% ز⣺21.182%

2018.03.04  PBֵͶʲ_1.1.2.180304
    δɹĹƱsell_every_dayĵƵ'open'Ϊ'every_bar'
زڣ2014-01-01  2018-01-30 ӻز
棺1032.76% 껯棺83.68% Alpha0.727 Beta0.569 Sharpe2.723 ʤʣ81.3% ز⣺21.91%

2018.03.04  PBֵͶʲ_1.1.1.180304
    ע
زڣ2014-01-01  2018-01-30 ӻز
棺1032.76% 껯棺83.68% Alpha0.727 Beta0.569 Sharpe2.723 ʤʣ81.3% ز⣺21.91%

2018.03.04  PBֵͶʲ_1.1.0.180304
    ֱֲ0.5Ϊ1󽨲3Ϊ1ע
زڣ2014-01-01  2018-01-30 ӻز
棺1032.76% 껯棺83.68% Alpha0.727 Beta0.569 Sharpe2.723 ʤʣ81.3% ز⣺21.91%

2018.03.04  PBֵͶʲ_1.0.0.180304
    ״ʽܣ޸ԭֹӯΪɴﵽ趨ǷᶨУֱ趨Ļسʱֹӯ
زڣ2014-01-01  2018-01-30 ӻز
棺729.21% 껯棺69.87% Alpha0.590 Beta0.562 Sharpe2.618 ʤʣ78.9% ز⣺12.994%

2018.01.31  PBֵͶʲ_0.1.5.180131
    ίɵȨ'by_cap_mean'ΪƱֵ'by_market_cap_percent' 
زڣ2014-01-01  2018-01-30 ӻز
棺711.27%껯棺68.95% Alpha0.582 Beta0.553 Sharpe2.543 ʤʣ79.4% ز⣺13.375%

2018.01.02  PBֵͶʲ_0.1.4.180102
    ʽɵĳ򣬿ʼо
زڣ2014-01-01  2017-12-16 ӻز
棺589.68%껯棺64.75% Alpha0.547 Beta0.560 Sharpe2.405 ʤʣ81.8% ز⣺12.971%

-------------------------------------------------------------------------------
'''






























